
// 编译器需要 c++ 14 的支持

#ifndef _MARRAY_HPP_
#define _MARRAY_HPP_

#include <cstring>
#include <cassert>
#include <type_traits>
// 最大不超过5是因为不想使用循环
template <typename T , unsigned D>
class Marray
{
public:
  // using Index = int;
  typedef int Index;
  using iter = T *;
  using const_iter = const T *;
  using value_type = T;

  Marray() noexcept = default;
  // 模板是使用什么就实例化什么,没有用到的话就不会产生实例
  // 不需要使用条件编译来精准定位, D 与参数数不匹配的话会编译错误

  // 静态数组不能放到初始化列表里  原因未知(已经初始化过了??)
  // 使用默认参数减少重复
  Marray(Index d0) noexcept
      : sz{d0}, elem{new T[d0]}
  {
    static_assert(D == 1, "error: dim must set one\n");
    dim[0] = d0;
  }
  Marray(Index d0, Index d1) noexcept
      : sz{d0 * d1}, elem{new T[sz]}
  {
    static_assert(D == 2, "error: dim must set two\n");
    dim[0] = d0;
    dim[1] = d1;
  }
  Marray(Index d0, Index d1, Index d2) noexcept
      : sz{d0 * d1 * d2}, elem{new T[sz]}
  {
    static_assert(D == 3, "error: dim must set three\n");
    dim[0] = d0;
    dim[1] = d1;
    dim[2] = d2;
  }
  Marray(Index d0, Index d1, Index d2, Index d3) noexcept
      : sz{d0 * d1 * d2 * d3}, elem{new T[sz]}
  {
    static_assert(D == 4, "error: dim must set four\n");
    dim[0] = d0;
    dim[1] = d1;
    dim[2] = d2;
    dim[3] = d3;
  }
  Marray(Index d0, Index d1, Index d2, Index d3, Index d4) noexcept
      : sz{d0 * d1 * d2 * d3 * d4}, elem{new T[sz]}
  {
    static_assert(D == 5, "error: dim must set five\n");
    dim[0] = d0;
    dim[1] = d1;
    dim[2] = d2;
    dim[3] = d3;
    dim[4] = d4;
  }

  Marray(const Marray &src) noexcept;
  Marray &operator=(const Marray &src) noexcept;
  Marray(Marray &&src) noexcept;
  Marray &operator=(Marray &&src) noexcept;
  ~Marray() { delete[] elem; }

  template <typename C>
  inline Marray &operator=(const C a) noexcept;

  iter data() { return elem; }
  const_iter data() const { return elem; }
  Index size() const noexcept { return sz; }

  Index dim1() const { return dim[0]; }
  // typename std::enable_if<(D == 2U || D == 3U || D == 4U || D == 5U), int>::type
  Index dim2() const
  {
    static_assert(1 < D, "if dim2 being called, the dimension must >= 2 ");
    return dim[1];
  }
  // std::enable_if_t<D == 3 || D == 4 || D == 5, int>
  Index dim3() const
  {
    static_assert(2 < D, "if dim3 being called, the dimension must >= 3 ");
    return dim[2];
  }
  // std::enable_if_t<D == 4 || D == 5, int>
  Index dim4() const
  {
    static_assert(3 < D, "if dim4 being called, the dimension must >= 4 ");
    return dim[3];
  }
  // std::enable_if_t<D ==5U, int>
  Index dim5() const
  {
    static_assert(4 < D, "if dim5 being called, the dimension must >= 5 ");
    return dim[4];
  }

  T& operator()(Index i) noexcept 
  {
    static_assert(D == 1, "one index, one dimension");
    assert(-1 < i && i < dim[0]);
    return elem[i];
  }
  T& operator()(Index i, Index j) noexcept 
  {
    static_assert(D == 2, "two index, two dimension");
    assert(-1 < i && i < dim[0] && -1 < j && j < dim[1]);
    return elem[i*dim[1] + j];
  }


private:
  Index dim[5]{0};
  Index sz{0};
  T *elem{nullptr};
  // 最后一个元素放置 size

  inline void copy_from(const Marray &src) noexcept;
  inline void move_from(Marray &src) noexcept;
};

template <typename T, unsigned D>
void Marray<T, D>::copy_from(const Marray &src) noexcept
{
  sz = src.sz;
  elem = new T[sz];
  memcpy(elem, src.elem, sizeof(T) * sz);
  dim[0] = src.dim[0];
  dim[1] = src.dim[1];
  dim[2] = src.dim[2];
  dim[3] = src.dim[3];
  dim[4] = src.dim[4];
}

template <typename T, unsigned D>
void Marray<T, D>::move_from(Marray &src) noexcept
{
  sz = src.sz;
  elem = src.elem;
  dim[0] = src.dim[0];
  dim[1] = src.dim[1];
  dim[2] = src.dim[2];
  dim[3] = src.dim[3];
  dim[4] = src.dim[4];
  src.sz = 0;
  src.elem = nullptr;
  src.dim[0] = src.dim[1] = src.dim[2] = src.dim[3] = src.dim[4] = 0;
}

template <typename T, unsigned D>
Marray<T, D>::Marray(const Marray &src) noexcept
{
  copy_from(src);
}

template <typename T, unsigned D>
Marray<T, D> &Marray<T, D>::operator=(const Marray &src) noexcept
{
  // 检测自赋值
  if (&src == this)
    return *this;
  delete[] elem;
  copy_from(src);
  return *this;
}

template <typename T, unsigned D>
Marray<T, D>::Marray(Marray &&src) noexcept
{
  move_from(src);
}

template <typename T, unsigned D>
Marray<T, D> &Marray<T, D>::operator=(Marray &&src) noexcept
{
  // 自移动就不检测了,除非自己想不开才自移动
  delete[] elem;
  move_from(src);
  return *this;
}

template <typename T, unsigned D>
template <typename C>
Marray<T, D> &Marray<T, D>::operator=(const C a) noexcept
{
  for (int i = 0; i != sz; ++i)
    elem[i] = a;
  return *this;
}

#endif